import 'dart:async';
import 'package:flutter_application_cyber/net/cn_net_helper.dart';
import 'package:flutter_application_cyber/model/cn_net_response.dart';
import 'cn_app_utils.dart';
import 'cn_device_utils.dart';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'cn_device_utils.dart';
import 'package:flutter_application_cyber/model/cn_user_default_cache.dart';
import 'package:flutter_application_cyber/model/cn_object_cache.dart';

/// 打点类型
///
enum LogType {
  globalBehavior('event', 'global_behavior', 'event'),
  clickEvent("event", "click", "event");

  final String logType;
  final String subType;
  final String behavior;

  const LogType(this.logType, this.subType, this.behavior);
}

// 打点管理
class CnLogManger {
  static final CnLogManger _instance = CnLogManger._internal();
  factory CnLogManger() {
    return _instance;
  }
  CnLogManger._internal();

  static const String tag = "LogManger"; // 日志标签
  static const int limitSize = 20; // 打点任务最多缓存长度
  static int _serialId = 0;
  // 每次启动App该值会修改
  static String launcherId = CnDeviceUtils.generateMd5(
      '${DateTime.now().millisecondsSinceEpoch}${CnDeviceUtils.getDeviceId()}');
  final List<Map<String, dynamic>> cacheList = [];
  bool _isWaitingForSend = false; // 是否需要延迟上报

  /// 上报日志
  void putLog(LogType logType, Map<String, dynamic>? event) {
    if (logType.logType.isEmpty ||
        logType.subType.isEmpty ||
        logType.behavior.isEmpty ||
        event == null ||
        event.isEmpty) {
      return;
    }
    _buildItemData(logType.logType, logType.subType, logType.behavior, event)
        .then((value) => {cacheList.insert(0, value), sendDelayed()});
  }

  /// 延时发送日志
  void sendDelayed() {
    if (_isWaitingForSend) {
      return;
    }
    _isWaitingForSend = true;
    Timer(const Duration(milliseconds: 2000), () {
      _isWaitingForSend = false;
      sendLog(false);
    });
  }

  /// 发日志打点
  void sendLog(bool forceUploadAll) {
    try {
      List<Map<String, dynamic>> sendList = [];
      if (cacheList.isEmpty) {
        return;
      } else if (cacheList.length >= limitSize && !forceUploadAll) {
        sendList.addAll(cacheList.sublist(0, limitSize));
        cacheList.removeRange(0, limitSize);
      } else {
        sendList.addAll(cacheList);
        cacheList.clear();
      }
      _doUpload(sendList, true);
    } catch (e) {}
  }

  /// 立马发送日志
  void putLogRightNow(LogType logType, Map<String, dynamic>? event) {
    if (logType.logType.isEmpty ||
        logType.subType.isEmpty ||
        logType.behavior.isEmpty ||
        event == null ||
        event.isEmpty) {
      return;
    }
    Map<String, dynamic> itemData;
    List<Map<String, dynamic>> list = [];

    _buildItemData(logType.logType, logType.subType, logType.behavior, event)
        .then((value) =>
            {itemData = value, list.add(itemData), _doUpload(list, false)});
  }

  /// 执行上传
  Future<void> _doUpload(
      List<Map<String, dynamic>> sendList, bool isContinue) async {
    CnNetHelper.logPost(sendList,
        (HDHResponseData configData, bool result, String msg) {
      //上报成功
    });
  }

  Future<Map<String, dynamic>> _buildItemData(String logType, String subType,
      String behavior, Map<String, dynamic>? event) async {
    Map<String, dynamic> itemData = {};
    itemData["data"] = [event];
    itemData["log_type"] = 'event';
    itemData["subtype"] = 'global_behavior';
    itemData["behavior"] = 'event';
    itemData["device-id"] = await CnDeviceUtils.getDeviceId();
    itemData["user_id"] = await CnUserDefaultCacheHelper.getUserId();
    itemData["pkg"] = await CnAppUtils.getPackageName();
    itemData["chn_id"] = '';
    itemData["ver"] = await CnAppUtils.getVersionName();
    itemData["platform"] = 'iOS';
    itemData["model"] = await CnDeviceUtils.getModel();
    itemData["p_ver"] = await CnAppUtils.getVersionNumber();
    itemData["lan_id"] = launcherId;
    itemData["sec_id"] = _serialId++;
    itemData["sys_lan"] = CnObjectCache.getTopContext() != null
        ? Localizations.localeOf(CnObjectCache.getTopContext()!).languageCode
        : 'en';
    itemData["country"] = await CnUserDefaultCacheHelper.getCountry();
    itemData["tm"] = DateTime.now().millisecondsSinceEpoch;
    print(itemData);
    return itemData;
  }
}
